<?php

namespace seecms;

/**
 * @method static user($name)
 * @method static menu($name)
 * @method static rule($name)
 * @method static message($name)
 * @method static attachment($name)
 * @method static switch ($name)
 * @method static pageTitle($name)
 * @method static login($name)
 * @method static site($name)
 * @method static smtp($name)
 * @method static upload($name)
 * @method static sms($name)
 * @method static backup($name)
 * @method static cache($name)
 * @method static btn($name)
 * @method static permission($name)
 * @method static dialog($name)
 * @method static operate($name)
 * @method static general($name)
 */
class SeeLang
{
    /**
     * @var SeeLang|null
     */
    protected static $instance = null;

    /**
     * 语言标记
     * @var string
     */
    protected $lang = 'zh-cn';

    /**
     * 语言数据包 分组,zh-cn/en-us
     * @var array
     */
    protected $data = [];

    protected $load_directory = [];

    protected function __construct()
    {

    }

    protected function __clone()
    {

    }


    /**
     * @return SeeLang
     */
    public static function instance(): SeeLang
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
            self::$instance->load_directory[] = __DIR__ . '/lang/';
        }

        return self::$instance;
    }

    /**
     * @param string $lang
     * @return true
     */
    public function switchLangSet(string $lang): bool
    {
        $this->lang = $lang;

        $combine = See::config()->lang->loadCombine();
        $filename = $combine . $lang . '.php';

        if ($combine && is_file($filename) && !See::config()->debug()) {
            $this->data[$lang] = include $filename;
            return true;
        }

        // 加载配置文件中的语言包
        $directory = See::config()->lang->loadDirectory();
        $directory = array_merge(self::$instance->load_directory, See::module()->getLang(), $directory);

        foreach ($directory as $item) {
            self::$instance->loadDir($item, $lang);
        }

        $this->combine($lang);

        return true;
    }

    /**
     * @return string
     */
    public function getLangSet(): string
    {
        return $this->lang;
    }

    /**
     * @param $name
     * @param string $lang
     * @return array
     */
    public function getLangGroup($name, string $lang = ''): array
    {
        $lang = $lang ?: $this->lang;
        return $this->data[$lang][$name] ?: [];
    }

    /**
     * @param string $lang
     * @return array|mixed
     */
    public function getData(string $lang = '')
    {
        $lang = $lang ?: $this->lang;

        return $this->data[$lang] ?: [];
    }

    /**
     * 追加语言包目录
     * @param $directory
     * @return void
     */
    public function appendDirectory($directory)
    {
        self::$instance->load_directory[] = $directory;
    }

    /**
     * 加载目录下的语言包
     * @param string $dir
     * @param string $lang
     * @return void
     */
    public function loadDir(string $dir, string $lang = '')
    {
        $dir = rtrim($dir, '/');
        $lang = $lang ?: ($_COOKIE['seecms_lang'] ?? self::$instance->lang);
        if (!preg_match("/{$lang}\$/", $dir)) {
            $dir = $dir . '/' . $lang;
        }

        if (is_dir($dir)) {
            $lang_files = glob($dir . '/*.php');
            if ($lang_files) {
                foreach ($lang_files as $file) {
                    self::$instance->load($file, $lang);
                }
            }
        }
    }

    /**
     * 加载语言包
     * @param string $file
     * @param string $lang
     * @return array
     */
    public function load(string $file, string $lang = ''): array
    {
        $lang = $lang ?: $this->lang;

        $group = [];

        if (is_file($file)) {
            $result = include $file;
            if (is_array($result)) {
                $group = array_change_key_case($result) + $group;
            }
        }

        $filename = pathinfo($file, PATHINFO_FILENAME);

        if ($group) {
            if (isset($this->data[$lang][$filename])) {
                $this->data[$lang][$filename] = $group + $this->data[$lang][$filename];
            } else {
                $this->data[$lang][$filename] = $group;
            }
        }

        return $this->data;
    }

    protected function combine($lang = '')
    {
        $lang = $lang ?: $this->lang;

        $combine = See::config()->lang->loadCombine();
        $filename = $combine . $lang . '.php';

        $json = json_encode($this->data);
        $json = var_export(json_decode($json, true), true);
        $json = preg_replace('/\s+/', ' ', $json);

        if ($combine) {
            file_put_contents($filename, "<?" . "php \n return " . $json . ';');
        }
    }

    /**
     * @param array $lang
     * @return void
     */
    public function refresh(array $lang)
    {
        $this->data[$this->lang] = $lang;
    }

    /**
     * @param array $data
     * @param string $lang
     * @return void
     */
    public function append(array $data, string $lang = '')
    {
        $lang = $lang ?: $this->lang;

        if (!isset($this->data[$lang])) {
            $this->data[$lang] = [];
        }

        if ($this->data[$lang]) {
            $data = array_merge($this->data[$lang], $data);
        }

        $this->data[$lang] = $data;

        $this->combine($lang);
    }


    /**
     * @param string|null $name
     * @param array $vars
     * @param string $lang
     * @return array|mixed|string|string[]
     */
    public function get(string $name = null, array $vars = [], string $lang = '')
    {
        if (is_null($name)) {
            return '';
        }

        $lang = $lang ?: $this->lang;

        if (strpos($name, '.')) {
            [$name1, $name2] = explode('.', $name, 2);
            $value = $this->data[$lang][strtolower($name1)][$name2] ?? null;
        } else {
            $value = $this->data[$lang][strtolower($name)] ?? null;
        }

        // 从global中取值
        if (empty($value)) {
            $value = $this->data[$lang]['__global__'][strtolower($name)] ?? $name;
        }

        // 变量解析
        if (!empty($vars) && is_array($vars)) {
            if (key($vars) === 0) {
                // 数字索引解析
                array_unshift($vars, $value);
                $value = call_user_func_array('sprintf', $vars);
            } else {
                // 关联索引解析
                $replace = array_keys($vars);
                foreach ($replace as &$v) {
                    $v = "{:{$v}}";
                }
                $value = str_replace($replace, $vars, $value);
            }
        }

        return $value;
    }

    /**
     * 将语言包中的组名字取得的数据跟__global__组进行合并
     * @param string|null $name 语言包中的组名称
     * @param string $lang
     * @return array
     */
    public function global(string $name = null, string $lang = ''): array
    {
        if (is_null($name)) {
            return [];
        }

        $lang = $lang ?: $this->lang;

        $global = $this->data[$lang]['__global__'] ?? [];
        $data = $this->data[$lang][strtolower($name)] ?? [];

        if (is_array($global) || is_array($data)) {
            return array_merge($global, $data);
        }

        return [];
    }

    /**
     * 静态代理
     * @param $name
     * @param $params
     * @return mixed|string
     */
    public static function __callStatic($name, $params)
    {

        $field = current($params);
        $field = trim($field);
        if (empty($field)) {
            return '';
        }

        $group = self::$instance->data[self::$instance->lang][$name] ?? [];
        $value = $group[$field] ?? null;
        if ($value) {
            return $value;
        }

        $global = self::$instance->data[self::$instance->lang]['global'] ?? [];
        if ($global) {
            $value = $global[$field] ?? null;
        }

        if ($value) {
            return $value;
        }

        return $field;
    }
}